/*
 *Copyright (c) 2024 Black Sesame Technologies
 *
 *Licensed under the Apache License, Version 2.0 (the "License");
 *you may not use this file except in compliance with the License.
 *You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 *Unless required by applicable law or agreed to in writing, software
 *distributed under the License is distributed on an "AS IS" BASIS,
 *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *See the License for the specific language governing permissions and
 *limitations under the License.
*/

#include "common.h"

#define UNUSED 0
#define USED 1
#define HEAP_NOTFIND 0
#define HEAP_FOUND  1

#ifdef MALLOC_HEAP
static unsigned long HEAP_START = MALLOC_HEAP_START;
static unsigned long HEAP_END = MALLOC_HEAP_END;
#else
static unsigned long HEAP_START = 0x0;
static unsigned long HEAP_END = 0x0;
#endif
 
typedef struct _heap
{
	int size;
	int start;
	int end;
	int used;
	struct _heap *next;
	struct _heap *prv;
}heap;
 
static heap *heap_h;
static heap *heap_cur;
static heap *heap_mark;
static int heapnum=0;

void init_heap(void)
{
 
	heap_h = (heap *)HEAP_START;
	heap_h->size = (HEAP_END-HEAP_START)-sizeof(heap);
	heap_h->start = HEAP_START+sizeof(heap);
	heap_h->end = HEAP_END;
	heap_h->used = UNUSED;
	heap_h->next = NULL;
	heap_h->prv = NULL;
	heap_cur = heap_h;
	heapnum=0;
	
	hprintf(MESG, "HEAP_START=%08x\r\n", (const char *)HEAP_START);
	hprintf(MESG, "HEAP_END=%08x\r\n", (const char *)HEAP_END);	
	
	
	hprintf(MESG, "heap_h=0x%08x\r\n",(const char *)heap_cur);
	hprintf(MESG, "heap_h->start=%08x\r\n",(const char *)(heap_h->start));
	hprintf(MESG, "heap_h->size=0x%08x\r\n",(const char *)(heap_h->size));
	
}
 
void * xmalloc(unsigned int size)
{
 
	heap *new_bk;
	heap *p_bk;
	int stat=HEAP_NOTFIND;
	int num = 0;
	size = (size+7)&~7;
 
	heap_mark=heap_cur;
	while(heap_cur->next != heap_mark) {
 		if(NULL == heap_cur) {
 			heap_cur = heap_h;
 		}
  	
  		if(UNUSED == heap_cur->used) {
    		if(heap_cur->size > (size+sizeof(heap))) {	
       			new_bk = (heap*)((unsigned char *)heap_cur+(size+sizeof(heap)));
        		new_bk->size = heap_cur->size-(size+sizeof(heap));
        		new_bk->start = heap_cur->start+(size+sizeof(heap));
        		new_bk->end = heap_cur->end;
        		new_bk->used = UNUSED;
        		new_bk->next = heap_cur->next;
        		new_bk->prv = heap_cur;
        		heap_cur->used = USED;
        		heap_cur->size = size;
        		heap_cur->end = heap_cur->start+size;
        		heap_cur->next = new_bk;
        		stat = HEAP_FOUND;
				heapnum++;
				
        		hprintf(MESG, "heapnum:%d,heap:0x%08x,heapsize:%d\r\n", heapnum, (const char *)(heap_cur->start),size);
        		
				break;      
        	}
        
      	}
  		num++;
		
		if(num > 1000) {
			hprintf(MESG, "alloc error\r\n");
			return NULL;
		}
  		heap_cur = heap_cur->next;
  
  	}
  	
  	if(stat == HEAP_NOTFIND) {
  		hprintf(MESG, "malloc fail\r\n");
  		return NULL;
  	}
  	
 	p_bk = heap_cur;
  	
 	heap_cur = new_bk;
	
 	return ((heap *)((u32)p_bk + sizeof(heap)));
 } 
  
void xfree(void *block)
 
{	
	heap * p_bk;
	heap * prv_bk;
	heap * next_bk;
  
  	if(block==NULL) {
  		return ;
  	}
  	
  	p_bk = (heap *)((unsigned char *)block-sizeof(heap));
  	p_bk->used = UNUSED;
  	prv_bk = p_bk->prv;
  	next_bk = p_bk->next;
  	hprintf(MESG, "xfree\r\n");
  	if(prv_bk != NULL)
   	{
   		if(prv_bk->used==UNUSED)
      	{
      		prv_bk->size = prv_bk->size+p_bk->size+sizeof(heap);
       		prv_bk->end = p_bk->end;
       		prv_bk->next = p_bk->next;
       		p_bk = prv_bk;
			heapnum--;
       	}
   }  
  	if(next_bk != NULL)
  	{
  		if(next_bk->used == UNUSED)
     	{
     		p_bk->size = p_bk->size+next_bk->size+sizeof(heap);
     		p_bk->end = next_bk->end;
     		p_bk->next = p_bk->next;
			heapnum--;
     	}
  	}
   
   heap_cur = p_bk;
}  
